<?php
class CartWS_Model_Order 
{
	private $_config;

	public function __construct()
	{
		$this->_config = Zend_Registry::get('config');
	}
	/**
	 *
	 * Devuelve la linea de zonas a partir de un  parentId. El depth mas alto es 0
	 *
	 * @param integer $parentId
	 * @return mixed
	 */
	public function getZone( $parentId ) 
	{
		$zone = new CartWS_Model_Zone();
		return $zone->getZone( $parentId );
	}
	
	/**
     * Devuelve la info completa de una orden a partir de un orderId, 
     * 
     * esta orden tiene que ser del usuario que la pide.
     * 
     * @param integer $userId
     * @param string $credential
     * @param integer $orderId
     * @return array
     */
	public function getFullOrderInfo( $userId, $orderId)
	{
		$order['hdr'] = $this->getOrder(  $orderId );
		if( $order['hdr']['customer_id'] != $userId ) {
			throw new Ext_Exception('La orden no esta asociada a este usuario');
		}
		$order['lines'] = $this->getOrderLines( $orderId );
		$order['properties'] = $this->getOrderProperties( $orderId );
		return $order;	
	} 
	
	/**
	 *
	 * Devuelve un row con los datos de la orden
	 * @param integer orderId
	 * @return mixed Row
	 */
	private function _getOrder( $orderId ) 
	{
		$orderTable = new CartWS_Model_SalesOrderHdr();
		$orderRow = $orderTable->find( $orderId )->current();
		if( empty( $orderRow )) {
			throw new Ext_Exception( 'La orden no existe' );
		}
		return $orderRow;
	}

	/**
	 *
	 * Devuelve los datos de la orden
	 *
	 * @param integer OrderId
	 * @return array OrderRow
	 */
	public function getOrder( $orderId ) 
	{
		return $this->_getOrder($orderId)->toArray();
	}

	/**
	 *
	 * Retorna la orden Activa del cliente. Si no existe la crea
	 * @param integer $userId
	 * @param mixed $properties
	 * @return integer $orderId
	 */
	public function getActiveOrder( $userId, $properties = array() ) 
	{
		$orderTable = new CartWS_Model_SalesOrderHdr();
		$orderRow = $orderTable->getActiveOrderFromCustomer( $userId );
		if( $orderRow === false ) {
			$orderId =  $orderTable->createOrder( $userId, $properties );
			$this->setShippingMethod(
				$orderId, $this->getShippingMethodDefault()
			);
			return $orderId;
		}
		return $orderRow->sales_order_id;
	}

	/**
	 * Get Total Amount, devuelve un array con los montos totales
	 * @param integer $userId
	 * @return double Total
	 */
	public function getTotalAmount($userId ) 
	{
		$orderId = $this->getActiveOrder($userId);
		$order = new CartWS_Model_SalesOrderHdr();
		$row = $order->find($orderId)->current();
		if( count($row )) {
			return $row->total_amount;
		}
		return null;
	}

	/**
	 * Devuelve el costo de envio
	 *
	 * @param integer $orderId
	 * @return integer
	 */
	public function getShippingCost( $orderId ) 
	{
		$lineTable = new CartWS_Model_SalesOrderLine();
		return $lineTable->sumLines( $orderId, CartWS_Model_SalesOrderLine::LINE_TYPE_SHIPPING_COST );
	}
	
	/**
	 *
	 * Devuelve un array con id, y descripcion de las direcciones asociadas a un usuario
	 * @param integer userId
	 * @return array Address
	 */
	public function getAddress( $userId) 
	{
		$addressModel = new CartWS_Model_Address();
		$rowset =  $addressModel->getFromUserId( $userId );
		$address = array();
		foreach( $rowset as $row ) {
			$address[$row->address_id] = $row->name;
		}
		return $address;
	}

	/**
	 *
	 * Devuelve un array la info de una direccion
	 * @param integer $addressId
	 * @return array Address
	 */
	public function getAddressInfo( $addressId) 
	{
		$addressModel = new CartWS_Model_Address();
		$row =  $addressModel->find( $addressId )->current();

		if( count($row)) {
			$zoneModel = new CartWS_Model_Zone();
			$address = $row->toArray();
			$address['zone_info'] = $zoneModel->getInheritance( $row->zone_id );
			return $address;
		}
		return array();
	}

	/**
	 *
	 * Devuelve un array completo con todas las direcciones asociadas a un usuario
	 * @param integer customerId
	 * @return array Address
	 */
	public function getBookAddress( $customerId ) 
	{
		$addressModel = new CartWS_Model_Address();
		$rowset =  $addressModel->getFromUserId( $customerId );
		if( count( $rowset )) {
			return $rowset->toArray();
		}
		return array();
	}

	/**
	 *
	 * Agrega una direccion asociada a un usuario
	 * @param integer userId
	 * @param mixed Address
	 * @return boolean true|false
	 */
	public function addAddress( $userId, $address) 
	{
		$form = new CartWS_Form_Address();
		if ($form->isValid( $address )) {
			$addressModel = new CartWS_Model_Address();
			if( !empty( $address['address_id'] )) {
				$row = $addressModel->find($address['address_id'])->current();
				if( count( $row )) {
					$row->setFromArray( $form->getValues());
					$row->save();
					return true;
				}
			}
			$row = $addressModel->createRow();
			$row->customer_id = $userId;
			$row->setFromArray( $form->getValues() );
			$row->save();
			return true;
		}
		return false;
	}

	/**
	 *
	 * Establece el telefono de contacto para la orden
	 * @param integer userId
	 * @param string ContactPhone
	 * @return mixed true|false
	 */
	public function setContactPhone( $userId, $contactPhone ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderRow = $this->getOrder( $orderId );
		$orderRow->contact_phone = $contactPhone;
		$orderRow->save();
		return true;
	}

	/**
	 *
	 * Obtiene el telefono de contacto de la orden
	 * @return string ContactPhone
	 */
	public function getContactPhone( $userId ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderRow = $this->_getOrder( $orderId );
		return $orderRow->contact_phone;
	}

	/**
	 *
	 * Obtiene el la direccion de envio del producto
	 * @return string ShipAddress
	 */
	public function getShipAddress( $userId ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderRow = $this->_getOrder( $orderId );
		return $orderRow->ship_to_address_id;
	}

	/**
	 *
	 * Obtiene el la direccion de despacho de boleta de la orden
	 * @return string BillAddress
	 */
	public function getBillAddress( $userId) 
	{ 
		$orderId = $this->getActiveOrder( $userId  );
		$orderRow = $this->_getOrder( $orderId );
		return $orderRow->bill_to_address_id;
	}

	/**
	 * Retorna todas las ordenes cerradas de un cliente.
	 * @return array Orders
	 */
	public function getOrderHistory( $userId ) {
		$orderTable = new CartWS_Model_SalesOrderHdr();
		$orderRowset = $orderTable->getAllOrderClosedForCustomer( $userId );
		if( $orderRowset === false ) {
			return array();
		}
		return $orderRowset;
	}
	
	/**
	 *
	 * Obtiene el estado de la orden
	 * @param integer OrderId
	 * @return string Status
	 */
	public function getStatus( $orderId) 
	{
		if( empty( $orderId) ) {
			throw new Ext_Ext( 'El order no fue enviado' );
		}
		$orderRow = $this->_getOrder( $orderId );
		return $orderRow->status;
	}

	/**
	 *
	 * Establece el estado la orden
	 * @param integer OrderId
	 * @param string Status
	 * @return mixed true|false
	 */
	public function setStatus( $orderId, $status ) 
	{
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->status = $status;
		$orderRow->save();
		return true;
	}

	/**
	 *
	 * Cierra la orden Activa del cliente.
	 * @param integer OrderId
	 * @return boolean true|false
	 */
	public function closeOrder( $orderId ) 
	{
		try{
			$order = $this->getOrder( $orderId );
			//	Trackeamos la orden
			$result = $this->trackOrder( $orderId );
			if( $result === false ) {
				throw new Ext_Exception("La orden $orderId, no se pudo cerrar por que los datos no son validos ");
			}
			// Seteamos la orden como pagada
			$this->payOrder( $orderId );
			// Setear status de la orden segun pay Method
			$this->setStatus( $orderId, 'C');
			return true;
		}catch (Exception $e ) {
			;
		}
	}

	/**
	 *
	 * Agrega un muchos items a la orden. La idea es calcular el total una sola vez.
	 * Si existe un producto igual en la orden, le suma las cantidades.
	 * Si la cantidad final es menor a 1 se borra el item de la orden
	 * @param integer OrderId
	 * @param mixed Line
	 * @return Boolean True
	 */
	public function addOrderLines( $orderId, $lines ) 
	{
		$lineTable = new CartWS_Model_SalesOrderLine();
	
		foreach( $lines as $line ) {
			$lineTable->addOrderLine($orderId, $line);
		}
		$this->_setTotalAmount( $orderId );
		return true;
	}

	public function addOrderLine( $orderId, $line ) 
	{		
		$lineTable = new CartWS_Model_SalesOrderLine();
		
		$lineTable->addOrderLine($orderId, $line);
		$this->_setTotalAmount( $orderId );
		return true;
	}

	public function deleteLinesByType( $orderId, $types, $setTotal = true ) 
	{
		$lineTable = new CartWS_Model_SalesOrderLine();
		$lineTable->deleteLinesByType( $orderId, $types );
		if ( $setTotal ) {
			$this->_setTotalAmount( $orderId );
		}
	}


	private function _setTotalAmount( $orderId ) 
	{
		$lineTable = new CartWS_Model_SalesOrderLine();
		$total = $lineTable->sumLines( $orderId );
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->total_amount = $total;
		$orderRow->save();
	}

	/**
	 * Agrega propiedades a las lineas de una orden
	 * @param integer LineId
	 * @param mixed Properties
	 */
	public function addLineProperty( $lineId, $properties ) 
	{
		$linePropModel = new CartWS_Model_SalesLineProperty();
		$linePropModel->addProperties ( $lineId, $properties );
	}

	/**
	 *
	 * todas las propiedades de una linea
	 * @param integer LineId
	 * @return array Line
	 */
	public function getOrderLine( $lineId ) 
	{
		$lineTable = new CartWS_Model_SalesOrderLine();
		$row = $lineTable->find( $lineId )->current();
		return $row->toArray();
	}

	/**
	 *
	 * Devuelve las lineas de una orden
	 * @param integer OrderID
	 * @return array lineModel
	 */
	public function getOrderLines( $orderId ) 
	{
		$lineModel = new CartWS_Model_SalesOrderLine();
		$lines = $lineModel->getLinesFromOrder( $orderId );
		return $lines;
	}

	/**
	 *
	 * Establece la direccion de cobro para la orden
	 *
	 * @param integer AddressBillId
	 * @param integer $shippingMethodId
	 * @return boolean true
	 */
	public function setBillAddress( $userId, $billAddressId, $shippingMethodId = null ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->bill_to_address_id = $billAddressId;
		$orderRow->save();
		$this->setShippingMethod( $orderId );
		return true;
	}

	/**
	 *
	 * Establece la direccion de envio para la orden
	 *
	 * @param integer AddressShipId
	 * @param integer $shippingMethodId
	 * @return boolean true
	 */
	public function setShipAddress( $userId, $shipAddressId, $shippingMethodId = null ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->ship_to_address_id = $shipAddressId;
		if( empty($shippingMethodId )) {
			$orderRow->shipping_method_id = $this->getShippingMethodDefault();
		}else {
			$orderRow->shipping_method_id = $shippingMethodId;
		}

		$orderRow->save();
		$this->setShippingMethod( $orderId );
		return true;
	}

	/**
	 *
	 * Establece el metodo de pago para la orden
	 * @param integer OrderId
	 * @param integer PaymentMethdId
	 * @return boolean true
	 */
	public function setPaymentMethod( $orderId, $paymentMethodId ) 
	{
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->payment_method_id = $paymentMethodId;
		$orderRow->save();
		return true;
	}

	/**
	 *
	 * Agrga propiedades a una orden
	 * @param integer userId
	 * @param mixed properties
	 * @return boolean true|false
	 */
	public function addOrderProperty($userId, $properties ) 
	{
		$orderId = $this->getActiveOrder( $userId );
		$orderProperty = new CartWS_Model_SalesOrderHdrProperty();
		foreach( $properties as $property=>$value) {
			$orderProperty->addProperty($orderId, $property, $value);
		}
		return true;
	}
	
	/**
	 *
	 * Devuelve las  propiedades a una orden
	 * @param integer orderId
	 * @return array
	 */
	public function getOrderProperties( $orderId ) 
	{
		$orderProperty = new CartWS_Model_SalesOrderHdrProperty();
		$rowset = $orderProperty->fetchAll( 
			$orderProperty->select()->where('sales_order_id = ?', $orderId )
		);
		if ( count( $rowset ) ) {
			return $rowset->toArray();
		}
		return array();
		
	}

	/**
	 *
	 * (cacheable) Devuelve el listado de los metodos de pago
	 * @return array PaymentMethods
	 */
	public function getPaymentMethods() 
	{
		$paymentMethod = new CartWS_Model_PaymentMethod();
		return $paymentMethod->getActivedMethod();
	}

	/**
	 *
	 * Establece el tipo de envio de la orden
	 * @param integer OrderId
	 * @param integer ShippingMethodId
	 * @return boolean true
	 */
	public function setShippingMethod( $orderId, $shippingMethodId = null) 
	{
		$orderRow = $this->_getOrder( $orderId );
		if( empty( $shippingMethodId ) ){
			$orderRow->shipping_method_id = $this->calculateShippingMethod( $orderId );
		} else {
			$orderRow->shipping_method_id = $shippingMethodId;
		}
		$orderRow->save();
		return true;
	}
	
	/**
	 * Calcula el metodo de envio a partir de las direcciones de destino de la orden
	 * @param integer $orderId
	 * @return integer Shipping Method Id
	 */
	public function calculateShippingMethod( $orderId )
	{
		$order = $this->_getOrder( $orderId );
		$address = new CartWS_Model_Address();
		$row = $address->find($order->ship_to_address_id )->current();
		if( count( $row )) {
			if( $row->customer_id == $order->customer_id ) {
				return $this->_config->Shipping->method->chileexpress;
			}
		}
		$row = $address->find($order->bill_to_address_id )->current();
		if( count( $row )) {
			if( $row->customer_id == $order->customer_id ) {
				return $this->_config->Shipping->method->chileexpress;
			}
		}
		return $this->_config->Shipping->method->sucursal;
	}

	/**
	 *
	 * Establece que la orden se cobro
	 * @param integer OrderId
	 * @return mixed true|false
	 */
	public function payOrder( $orderId ) {
		$orderRow = $this->_getOrder( $orderId );
		$orderRow->pay_date = Ext_Db_Date::now();
		$orderRow->status = CartWS_Model_SalesOrderHdr::CLOSE_ORDER;
		$orderRow->save();
		return true;
	}

	/**
	 *
	 * Devuelve el Metodo de envio default para el sistema (cacheable)
	 * @return integer
	 */
	public function getShippingMethodDefault() 
	{
		return $this->_config->Shipping->method->chileexpress;
	}

	/**
	 * Recibe una orden y la envia al tracker
	 *
	 * @param integer $idOrden
	 * @return boolean true|false
	 * @todo Flag para saber si factura o no en vez de esto pasar un json con
	 * Title y Author productDescription
	 */
	public function trackOrder( $orderId ) 
	{
		error_log("llega a trackear");
		$organizationId = $this->_config->Tracker->organization->id;
		$trckrMsg = new Ext_Tracker_ImportMessage();
		$trckrMsg->setOrganizationId( $organizationId );
		$trckrModel = new CartWS_Model_Tracker();
		$result = $trckrModel->getOrderToTrack( $orderId );
		error_log("traemos la orden a trackear");
		if( isset( $_GET['test'])) {
			echo $orderId;
			Zend_Debug::dump($result);
			echo Zend_Json::encode ( $result );
		}
		$trckrMsg->setOrders( $result );
		$queue = new Ext_Queue(
		$this->_config->ActiveMq->queue->url,
		$this->_config->Tracker->queue->name
		);
		$message = $trckrMsg->getMessage();
		$queue->enqueue( $message );
		return true;
	}
}